#ifndef SOCKETANDSSL_H
#define SOCKETANDSSL_H
#include <QDebug>



#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 12345

extern "C"{
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <mysql/mysql.h>
#include <stdint.h>
#include <sqlite3.h>

    static int Operations(char *buffer, SSL *ssl);
    static int Communicate(char *buffer, SSL *ssl);
    static int Login(char *buffer, SSL *ssl);
    static SSL *Sync_init_ssl(int client_socket);
    static int Creat_client_socket();
    static int Connet_to_server(int client_socket);
    static int Ssl_connect(int client_socket,SSL *ssl);
    static int Register_request(char *buffer, SSL *ssl, char* input_register_username, int buffer_size);
    static void Fialnize(SSL *ssl, int client_socket, SSL_CTX *ctx);
    static void Print_welcome();
    static void Login_request(char *buffer, SSL *ssl, char* input_username, char* input_password);
    static int Register_set_password(char *buffer, SSL *ssl, char *input_register_username, int buffer_size);

}

class socketAndSSL
{

public:
    socketAndSSL();

public:
    static SSL *Sync_init_ssl(int client_socket){
        SSL_library_init();
        SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
        if (ctx == NULL) {
            printf("Error creating SSL context\n");
            return NULL;
        }

        SSL *ssl = SSL_new(ctx);

        SSL_set_fd(ssl, client_socket);

        return ssl;

    }

    static int Creat_client_socket(){
        int client_socket = socket(AF_INET, SOCK_STREAM, 0);
        if (client_socket < 0) {
            printf("Error creating client socket\n");
            return 1;
        }
        return client_socket;
    }

    static int Connet_to_server(int client_socket){
        struct sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
        server_addr.sin_port = htons(SERVER_PORT);

        if (connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
            printf("Error connecting to server\n");
            return -1;
        }else{
            printf("socket connect OK!\n");
        }
        return 0;
    }

    static int Ssl_connect(int client_socket,SSL *ssl){
        if (SSL_connect(ssl) < 0) {
            printf("Error connecting SSL\n");
            close(client_socket);
            return 1;
        }else{
            printf("SSL connect OK!\n");
        }
    }

    static int Register_request(char *buffer, SSL *ssl, char* input_register_username, int buffer_size){

        sprintf(buffer, "2_register");
        buffer[sizeof("2_register")] == '\0';
        SSL_write(ssl, buffer, strlen(buffer));
        memset(buffer, 0, sizeof(buffer));

        int ret = SSL_read(ssl, buffer, buffer_size);
        if(ret < 0){
            return -1;
        }
        if(buffer[0] == '1'){

            SSL_write(ssl, input_register_username, strlen(input_register_username));

            memset(buffer, 0, sizeof(buffer));

            ret = SSL_read(ssl, buffer, buffer_size);
            if(ret < 0){
                printf("Error when read from server.");
                return -1;
            }
            if(buffer[0] == '2'){
                qDebug() << "Name length out of max size, please try again!";
                return -2;
            }else{
                qDebug() << "Name set okay.";
                return 1;
            }
        }else{
            qDebug() << "fail";
            return -1;
        }
    }

    static int Register_set_password(char *buffer, SSL *ssl, char *input_register_password, int buffer_size){
        qDebug() << "Register_set_password enter.";
        sprintf(buffer, input_register_password);
        SSL_write(ssl, buffer, strlen(buffer));

        memset(buffer, 0, buffer_size);

        int len = SSL_read(ssl, buffer, buffer_size);
        qDebug() << buffer;
        if(len < 0){
            return -1;
        }
        if(buffer[0] == '5'){
            memset(buffer, 0 ,buffer_size);
            len = SSL_read(ssl, buffer, buffer_size);
            qDebug() << "pass set OK!";
            if(len < 0){
                return -1;
            }
            if(buffer[0] == '6'){
                qDebug() << "allset.";
                return 1;
            }
        }else{
            return -2;
        }
    }

    static int Operations(char *buffer, SSL *ssl){
        char log_flag;
        while(1){
            log_flag = getchar();
            if(log_flag == 'L'){
                sprintf(buffer, "login", strlen("login"));
                SSL_write(ssl, buffer, strlen(buffer));
                Login(buffer, ssl);
                Communicate(buffer, ssl);
            }else if(log_flag == 'R'){

            }else{
                printf("Please type S or L.\n");
            }
            memset(buffer, 0, sizeof(buffer));
        }
        return 0;
    }

    static int Login_request(char *buffer, SSL *ssl, char* input_username, char* input_password, int buffer_size){
        memset(buffer, 0, buffer_size);

        SSL_write(ssl, "login", strlen("login"));
        int len = SSL_read(ssl, buffer, buffer_size);
        printf("%d\n%s\n",buffer_size,buffer);
        if(len < 0){
            printf("Unexpect disconnect.\n");
        }
        if(!strcmp(buffer, "login_verify_start")){
            printf("login_verify_start recive OK\n");
            memset(buffer, 0, buffer_size);

            sprintf(buffer,input_username);
            SSL_write(ssl, buffer, strlen(buffer));
            memset(buffer, 0, buffer_size);

            int len = SSL_read(ssl, buffer, buffer_size);
            if(len < 0){
                printf("Unexpect disconnect.\n");
                return -1;
            }
            if(!strcmp(buffer, "username_input_done")){
                printf("username_input_done recive OK\n");
                sprintf(buffer,input_password);
                SSL_write(ssl, buffer, strlen(buffer));
                int len = SSL_read(ssl, buffer, buffer_size);
                if(len < 0){
                    printf("Unexpect disconnect.\n");
                    return -1;
                }
                if(!strcmp(buffer, "password_input_done")){
                    printf("password_input_done recive OK\n");
                    memset(buffer, 0, buffer_size);

                    SSL_read(ssl, buffer, buffer_size);
                    if(len < 0){
                        printf("Unexpect disconnect.\n");
                        return -1;
                    }
                    if(!strcmp("0\033[0;34mConnetion authorized!\033[0m\nPermition level \033[0;31m2\033[0m.\nWelcome back!\n",buffer)){
                        return 1;
                    }

                }
            }
        }
        return 0;
    }

    static int Communicate(char *buffer, SSL *ssl){
        while(1){
            write(STDOUT_FILENO,"Just say sth.:",sizeof("Just say sth.:"));
            read(STDIN_FILENO, buffer, sizeof(buffer));
            SSL_write(ssl, buffer, strlen(buffer));

            int len = SSL_read(ssl, buffer, sizeof(buffer)-1);
            if (len < 0) {
                printf("Error reading from SSL connection\n");
            }
            memset(buffer, 0, sizeof(buffer));

        }
    }

    static void Fialnize(SSL *ssl, int client_socket, SSL_CTX *ctx){
        SSL_shutdown(ssl);
        close(client_socket);

        SSL_CTX_free(ctx);
    }

    void Print_welcome(){
        printf("Welcome!\nEnter \033[0;31mL/R\033[0m to login or register.\n");
    }

public:

};

#endif // SOCKETANDSSL_H
